#ifndef __QE_DMAENGINE_H__
#define __QE_DMAENGINE_H__



#include "qe_device.h"



typedef enum {
    QE_DMA_COMPLETE,
    QE_DMA_IN_PROGRESS,
    QE_DMA_PAUSE,
    QE_DMA_ERROR,
} qe_dma_status;

typedef enum {
    QE_DMA_MEMCPY,
    QE_DMA_SLAVE,
    QE_DMA_CYCLIC,
} qe_dma_type;

typedef enum {
    QE_DMA_MEM_TO_MEM,
    QE_DMA_MEM_TO_DEV,
    QE_DMA_DEV_TO_MEM,
    QE_DMA_DEV_TO_DEV
} qe_dma_direction;

typedef enum {
	QE_DMA_PREP_INTERRUPT = (1 << 0),
	QE_DMA_CTRL_ACK = (1 << 1),
	QE_DMA_PREP_PQ_DISABLE_P = (1 << 2),
	QE_DMA_PREP_PQ_DISABLE_Q = (1 << 3),
	QE_DMA_PREP_CONTINUE = (1 << 4),
	QE_DMA_PREP_FENCE = (1 << 5),
	QE_DMA_CTRL_REUSE = (1 << 6),
	QE_DMA_PREP_CMD = (1 << 7),
} qe_dma_ctrl_flags;

typedef void (*qe_dma_tx_callback)(void *args);

typedef struct
{
    qe_dma_direction direction;
    qe_ubase src_addr;
    qe_ubase dst_addr; 
    qe_u8 src_addr_width;
    qe_u8 dst_addr_width;
    qe_u32 src_maxburst;
    qe_u32 dst_maxburst;
    qe_u32 src_port_window_size;
    qe_u32 dst_port_window_size;
} qe_dma_config;

struct qe_dma_device;
typedef struct qe_dma_device qe_dma_dev;

struct qe_dma_channel;
typedef struct qe_dma_channel qe_dma_chan;


typedef struct qe_dma_tx_descriptor
{
    qe_dma_ctrl_flags flags;
    qe_dma_chan *chan;
    void (*tx_submit)(struct qe_dma_tx_descriptor *tx);
    qe_dma_tx_callback callback;
} qe_dma_tx_desc;

typedef struct
{
    qe_dma_chan *(*get_chan)(qe_dma_dev *dev, qe_int id);
    qe_ret (*alloc_chan)(qe_dma_chan *chan);
    void (*free_chan)(qe_dma_dev *dev, qe_dma_chan *chan);

    qe_ret (*config)(qe_dma_chan *chan, qe_dma_config *config);

    void (*device_issue_pending)(qe_dma_chan *chan);
} qe_dma_ops;

typedef struct qe_dma_device
{
    qe_dev dev;
    qe_list channels;

    const qe_dma_ops *ops;
} qe_dma_dev;

typedef struct qe_dma_channel
{
    qe_dma_dev *dev;
    qe_int chan_id;
    qe_list list;
    qe_uint reference;
    qe_ptr priv;
} qe_dma_chan;



qe_dma_chan *qe_dma_request_chan(qe_dma_dev *dev, qe_int id);

qe_ret qe_dma_slave_config(qe_dma_chan *chan, qe_dma_config *config);

qe_dma_tx_desc *
qe_dma_prep_interleaved_dma(qe_dma_chan *chan);

void qe_dma_submit(qe_dma_tx_desc *desc);

void qe_dma_async_issue_pending(qe_dma_chan *chan);



#endif /* __QE_DMAENGINE_H__ */